import mx.utils.Delegate;

import gugga.application.ApplicationController;
import gugga.application.NavigationManager;
import gugga.application.Section;
import gugga.application.SectionsTransition;
import gugga.commands.CommandManager;
import gugga.commands.NavigationCommand;
import gugga.common.ITask;
import gugga.navigation.MenuNavigation;
import gugga.navigation.NavigationButton;
import gugga.sequence.ExecuteMethodTask;
import gugga.sequence.TaskSequence;
import gugga.utils.DebugUtils;

import navigationWithCommands.AboutSection;

/**
 * Please note that the base class (ApplicationController) implements the INavigationCommandReceiver interface. 
 * 
 * @author bony
 */
class navigationWithCommands.Application 
	extends ApplicationController
{ 
	// List all the application fields here. 
	private var mMainNavigation:MenuNavigation;
	
	private var mAboutButton:NavigationButton;
	private var mWhyButton:NavigationButton;
	private var mContactButton:NavigationButton;
	
	private var mAboutSection:AboutSection;
	private var mWhySection:Section;
	private var mContactSection:Section;

	private var mUndo:NavigationButton;
	private var mRedo:NavigationButton;
	
	//constructor	
	public function Application() 
	{
		// The constructor of the super class must be called.
		super();
		
		// The function getComponent creates a mapping between the instances on the scene and
		// the member variables of the Application class.
		mMainNavigation = getComponent("PrimaryNavigation");
		
		mAboutSection = getComponent("AboutSection");	
		mWhySection = getComponent("WhySection");	
		mContactSection = getComponent("ContactSection");	

		mUndo = getComponent("btnUndo");	
		mRedo = getComponent("btnRedo");	
				
		// Register instance of Application in the _global object, which is globally visible.
		// This allows external content to access application without using of singleton pattern. 
		_global["ApplicationController"] = this;
	}
	
	// All Objects instantiated inside the Application inherit UIComponentEx except macromedia components.
	// This function is required because we have to make sure that 
	// all objects inside the Application are associated with their respective classes and are avaialable and ready to work.
	// All sections are phisically nested inside the main Application and their initialization is not immediate.
	// Before execution of that function you cannot call any event related methods or mixin related methods of the objects.
	
	public function initUI()
	{
		// The constructor of the super class must be called.
		super.initUI();
		
		//  Set initial state of undo /redo controls.  
		updateUndoState();
		
		// The button mUndo listens to the event click and executes the method onUndo.
		mUndo.addEventListener("click",Delegate.create(this, onUndo));
		// The button mRedo listens to the event click and executes the method onRedo.
		mRedo.addEventListener("click",Delegate.create(this, onRedo));
		
		//Command manager is responsible for keeping track of all reversible actions done within system. 
		// We add Event listener to its event  in order to update the state of the buttons redo and undo after every command. 
		CommandManager.Instance.addEventListener("commandBufferContentChanged",
			Delegate.create(this, updateUndoState));
		
		// Configure main navigation.
		configureMenu();
		
		// Register all the sections in the application.
		registerSections();
				
		// Open default section.				
		// Set navigation state. Should be set only the first time.	
		// Add that tasks in the initializing Sequence.	
		var openDefaultSectionTask:ITask = ExecuteMethodTask.create(this,this.openSection, ["About"]);
		var markNavigationTask:ITask = ExecuteMethodTask.create(NavigationManager.Instance,NavigationManager.Instance.markNavigations, ["About"]);		var startNavigationsTask:ITask = ExecuteMethodTask.create(NavigationManager.Instance,NavigationManager.Instance.startNavigations);
		
		var initializingSequence: TaskSequence = new TaskSequence(); 
		
		// We have to include the default sections controller Initializing Sequence
		// in order to keep the class functional.
		initializingSequence.addTask(mSectionsControllerInitializingSequence);
		initializingSequence.addTask(openDefaultSectionTask);
		initializingSequence.addTask(markNavigationTask);		initializingSequence.addTask(startNavigationsTask);
		
		this.registerInitializingTask(initializingSequence);
					
		// Trigger initializing sequence.
		initialize();			
			
		// Activating sequence		
		// Using default activating sequence.
		
		// Open sequence		
		// Using default open sequence.
		
		// Close sequence		
		// Using default close sequence.    	
		
	}
	
	public function configureMenu()
	{
		mMainNavigation.registerChildSubItem("btnAbout","About",null, new NavigationCommand("About"));
		mMainNavigation.registerChildSubItem("btnWhy","Why",null, new NavigationCommand("Why"));
		mMainNavigation.registerChildSubItem("btnContact","Contact", null, new NavigationCommand("Contact"));
		
		NavigationManager.Instance.registerNavigation(mMainNavigation, "MainNavigation");	
	}
	
	public function registerSections()
	{
		registerChildSection("AboutSection","About");
		registerChildSection("WhySection","Why");
		registerChildSection("ContactSection","Contact");
	}
	
	// This property holds the current opened section's path. 
	// It is used as memento (state data) of the application. (See Memento Design Pattern) 
	private var mSectionPath:String;

	// Overwrite the method "openSection", in order to set the mSectionPath property. 
	public function openSection(aSectionPath:String) : SectionsTransition
	{
		mSectionPath = aSectionPath;
		return super.openSection(mSectionPath);				
	}
	
	private function updateUndoState() : Void 
	{	
		DebugUtils.trace("UPDATE UNDO STATE");
		
		mUndo.Enabled = CommandManager.Instance.hasUndoableActions();
		mRedo.Enabled = CommandManager.Instance.hasRedoableActions();		
	}

	private function onUndo() : Void 
	{
		CommandManager.Instance.undo();
	}
	
	private function onRedo() : Void 
	{
		CommandManager.Instance.redo();	
	}

}